#ifndef __TTDS_ttds_cjobQ_H
#define __TTDS_ttds_cjobQ_H
/**
 * @file ttds_cjobq.h
 * @author liangyaozhan (262666882@qq.com)
 * @brief 
 * @version 0.1
 * @date 2022-09-03
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include <stdint.h>
#include <setjmp.h>

#include "ttds/ttds_config.h"
#include "ttds/ttds_queue.h"

#ifndef TTDS_STATIC_ALLOC_COUNT 
#define TTDS_STATIC_ALLOC_COUNT 16
#endif
#ifndef TTDS_CJOB_EXTEND
#define TTDS_CJOB_EXTEND(x) void *x[2]
#endif


#ifdef __cplusplus
extern "C"
{
#endif

struct ttds_cjobq;
typedef struct ttds_cjobq ttds_cjobq_t;

struct ttds_cjob_transaction
{
	ttds_queue_t list_suspended;
	ttds_queue_t node_in_jq;
    uint32_t in_running_q_count;
};
typedef struct ttds_cjob_transaction ttds_cjob_transaction_t;
/**
 * @brief 
 * 
 * @param p_this 
 */
void ttds_cjob_transaction_init(struct ttds_cjob_transaction *p_this);

#define WHEEL_SIZE 16
typedef struct _cwheel cwheel;

struct ttds_cjob
{
    /* data */
    void (*func)(struct ttds_cjob *p_job);
    void (*destroy)(struct ttds_cjob *p_job);
    void *args;
	ttds_queue_t node;
    struct ttds_cjob_transaction *p_master;
    uint32_t indexing;
    int ref;
    int32_t tick;
    struct ttds_cjobq *p_running_q;
    TTDS_CJOB_EXTEND(reserve);
};
typedef struct ttds_cjob ttds_cjob_t;

/**
 * @brief 
 * 
 * @param p_this 
 * @param f 
 * @param args 
 * @param d 
 * @param delay 
 */
void ttds_cjob_add_delay(const struct ttds_cjob* p_this, void (*f)(struct ttds_cjob*), void* args, void (*d)(struct ttds_cjob*), int delay);
/**
 * @brief 
 * 
 * @param p_this 
 * @param f 
 * @param args 
 * @param d 
 * @param delay 
 */
void ttds_cjob_add_seq_delay(const struct ttds_cjob* p_this, void (*f)(struct ttds_cjob*), void* args, void (*d)(struct ttds_cjob*), int delay);
/**
 * @brief 
 * 
 * @param p_this 
 * @param f 
 * @param args 
 * @param d 
 */
void ttds_cjob_add_seq(const struct ttds_cjob *p_this, void (*f)(struct ttds_cjob*), void*args, void (*d)(struct ttds_cjob*) );
/**
 * @brief 
 * 
 * @param p_this 
 */
void ttds_cjob_destroy(struct ttds_cjob*p_this);

/**
 * @brief 
 * 
 */
struct ttds_cjobq
{
    /* data */
    ttds_queue_t job_list;
    ttds_queue_t job_list_delayed;
    ttds_queue_t job_free;
    struct ttds_cjob *p_running_j;
    int32_t tick_next_timeout;
    int32_t tick_pass;
    void *p_lock;
#ifdef TTDS_USING_JOB_HOOK
    void (*hook)(void *arg);
    void *arg;
#endif
};

/**
 * @brief 
 * 
 * @param p_this 
 */
void ttds_cjobq_init(struct ttds_cjobq *p_this);
void ttds_cjobq_destroy( struct ttds_cjobq *p_this );

#ifdef USING_JOB_HOOK
void ttds_cjobq_set_newjob_hook( struct ttds_cjobq *p_this, void (*f)(void*), void *arg);
#endif

#ifndef TTDS_STATIC_ALLOC_COUNT
/**
 * @brief 
 * 
 * @param p_this 
 * @param pre_allocate_count 
 */
void ttds_cjobq_job_pre_allocate(struct ttds_cjobq *p_this, int pre_allocate_count);
#endif

/**
 * @brief 
 * 
 * @param p_this 
 * @param f 
 * @param args 
 * @param d 
 * @param delay 
 */
void ttds_cjobq_add_delay(struct ttds_cjobq *p_this, void (*f)(struct ttds_cjob*), void *args, void (*d)(struct ttds_cjob*), int delay );

/**
 * @brief 
 * 
 * @param p_this 
 * @param f 
 * @param args 
 * @param d 
 */
void ttds_cjobq_add(struct ttds_cjobq *p_this, void (*f)(struct ttds_cjob*), void *args, void (*d)(struct ttds_cjob*) );

/**
 * @brief 
 * 
 * @param p_this 
 * @param origin 
 * @param f 
 * @param args 
 * @param d 
 * @param delay 
 */
void ttds_cjobq_add_seq_begin_delay(struct ttds_cjobq *p_this,struct ttds_cjob_transaction *origin, void (*f)(struct ttds_cjob*), void*args, void (*d)(struct ttds_cjob*), int delay );

/**
 * @brief 
 * 
 * @param p_this 
 * @param origin 
 * @param f 
 * @param args 
 * @param d 
 */
void ttds_cjobq_add_seq_begin(struct ttds_cjobq *p_this,struct ttds_cjob_transaction *origin, void (*f)(struct ttds_cjob*), void*args, void (*d)(struct ttds_cjob*) );

/**
 * @brief 
 * 
 * @param p_this 
 * @param parent 
 * @param f 
 * @param args 
 * @param d 
 */
void ttds_cjobq_add_seq(struct ttds_cjobq *p_this,const struct ttds_cjob *parent, void (*f)(struct ttds_cjob*), void*args, void (*d)(struct ttds_cjob*) );

/**
 * @brief 
 * 
 * @param p_this 
 * @param parent 
 * @param f 
 * @param args 
 * @param d 
 * @param delay 
 */
void ttds_cjobq_add_seq_delay(struct ttds_cjobq *p_this,const struct ttds_cjob *parent, void (*f)(struct ttds_cjob*), void*args, void (*d)(struct ttds_cjob*), int delay );

/**
 * @brief poll the job queue
 * 
 * @param p_this 
 * @param tick_add if not 0, ttds_cjobq_poll_timer will called.
 * @param jb_parent 
 * @return int has more job
 */
int  ttds_cjobq_poll(struct ttds_cjobq *p_this, int tick_add, jmp_buf **jb_parent );

void ttds_cjobq_poll_timer(struct ttds_cjobq *p_this, int tick_add);
int ttds_cjobq_is_empty(struct ttds_cjobq *p_this );


#ifdef __cplusplus
}
#endif

#endif
